import re

from mongoengine import fields

from app.errors import ServerError
from app.db.models.packages import Packages, Feature
from app.libs.enums import ChargeType, LimitType, ENABLED_FUNC_TYPE, TaskType

required_base = {
    'chargeType': 'chargeType',
    'key': '英文名称',
    'name': '套餐/模块名称',
    'marks': '备注'
}

required_plan = {
    'domain': '资产数',
    'smsAlert': '短信数',
    'emailAlert': '邮件数',
    'maxPage': '扫描URL数',
    'alertGroup': '告警组',
    'alertReceiver': '告警人',
    'aviliableMaxHistory': '可用性历史数据存储天数',
    'sitePortrait': '可使用网站画像监测服务业务系统数',
}


charge_types = tuple(item.value for item in ChargeType)
task_type_patterns = f"^{'|'.join(tuple(item.value for item in TaskType if item != TaskType.site_portrait))}+?"
limit_allow_keys = ('total', 'limitType')


def get_checked_args(request_args):
    new_limit = {}
    feature = {}
    task_feature = {}
    required_plan_tuple = tuple(required_plan.keys())
    request_limit = request_args.get('limit', {})

    for k, v in required_base.items():
        if not request_args.get(k):
            raise ServerError(msg=f"'{v}' 为必填项")

    if Packages.objects.find({'key': request_args.get('key')}):
        raise ServerError(msg='英文名称重复')

    if charge_type := request_args.get('chargeType') not in charge_types:
        raise ServerError(msg="'chargeType' incorrect.")

    if charge_type == ChargeType.addition_package.value and not request_args.get('packageMarks'):
        raise ServerError(msg="'套餐限制' 为必填项")

    # check limit
    for k, modules in request_limit.items():
        if not (_item := request_limit.get(k)) or not int(_item.get('total', 0)):
            continue
        # plan required key
        elif charge_type == ChargeType.plan.value and k in required_plan_tuple:
            if not (_item := request_limit.get(k)) or not int(_item.get('total', 0)):
                raise ServerError(msg=f"'{required_plan.get(k)}' 为必填项")
        new_limit[k] = {_k: _item[_k] for _k in limit_allow_keys if _item.get(_k)}
        if res := re.match(task_type_patterns, k):
            _task_type = res.group()
            new_limit[k]['taskType'] = _task_type
            if "Manual" in k:
                task_feature[f"{_task_type}ManualTask"] = True
                if modules.get('limitType') in (LimitType.period.value, ):
                    task_feature[f"{_task_type}Task"] = True
            if "MaxFreq" in k or "MaxTask" in k:
                task_feature[f"{_task_type}Task"] = True
        else:
            feature[k] = True

    if not task_feature and charge_type == ChargeType.plan.value:
        raise ServerError(msg="监测项至少选择一项")

    feature.update(task_feature)
    request_args['feature'] = feature
    request_args['limit'] = new_limit

    # enable
    enable_tuple = ENABLED_FUNC_TYPE
    for enable in enable_tuple:
        if new_limit.get(enable):
            new_limit[f'{enable}Enable'] = new_limit[enable]

    return request_args


def get_plans_feature(features):
    feature = {}
    task_feature = {}

    for f, limit_type in features:
        if res := re.match(task_type_patterns, f):
            _task_type = res.group()
            if "Manual" in f:
                task_feature[f"{_task_type}ManualTask"] = True
                if limit_type in (LimitType.period.value,):
                    task_feature[f"{_task_type}Task"] = True
            if "MaxFreq" in f or "MaxTask" in f:
                task_feature[f"{_task_type}Task"] = True
        else:
            feature[f] = True
    feature.update(task_feature)
    # 只需要Feature中定义的功能
    result = Feature().to_dict()
    for k in result.keys():
        if v := feature.get(k):
            result.update({k: v})
    return result


def get_new_balance(func_type, total, plan):
    data = {
        f"set__balance__{func_type}__used": 0,
        f"set__balance__{func_type}__total": total,
        f"set__balance__{func_type}__number": 0,
        f"set__balance__{func_type}__time": 0,
        f"set__balance__{func_type}__limitType": plan.get("limitType"),
        f"set__balance__{func_type}__taskType": plan.get("taskType", ""),
    }
    return data
